import { Upload } from "element-ui";
import slotsVnode from "@/components/mixins/slotsVnode";
/*
 * cUpload 上传文件
 * maxSize 默认为1G
 * v-model
 * 文件超过限制 给出提升
 *  */

const cUpload = {
  name: "cUpload",
  model: {
    prop: "fileList", // 没有用来回显,会影响视觉闪动,请使用fileList回显,fileList改成会触发$emit('change')
    event: "change",
  },
  props: {
    ...Upload.props,
    action: {
      // c-upload 设置了默认值action为uploadUrl
      type: String,
      required: false,
    },
    maxSize: {
      // 最大上传文件 默认1G
      type: Number,
      default: 1024, //单位为“兆”
    },
    minSize: {
      // 最小上传文件
      type: Number,
    },
    uploadType: {
      // 若传入dh,代表大华的上传，否则战勤的上传
      type: String,
    },
  },
  inheritAttrs: false,
  mixins: [slotsVnode],
  data() {
    return {
      uploadUrl: "/api/file/upload", // 上传接口地址
    };
  },
  watch: {
    uploadType: {
      // 根据type判断使用大华接口还是战勤接口
      handler(value) {
        this.uploadUrl =
          value === "dh" ? "/api/system/common/uploadICC" : "/api/file/upload";
      },
      immediate: true,
    },
  },
  methods: {
    fileBeforeUpload(file) {
      /*
       *上传文件之前的钩子，参数为上传的文件，
       * 若返回 false 或者返回 Promise 且被 reject，则停止上传。
       **/
      const bUpload = this.$props.beforeUpload;
      const { name: fileName } = file;
      const lastIdx = fileName.lastIndexOf(".");
      const fileSuffix = fileName.slice(lastIdx).toLowerCase();
      const acceptArr = this.accept ? this.accept.split(",") : [];
      if (fileName.length > 100) {
        this.$message.warning("文件名不得超过100字符");
        return false;
      }
      if (this.accept && !acceptArr.includes(fileSuffix)) {
        this.$message.warning("上传文件格式有误，请重新上传");
        return false;
      }
      if (bUpload) {
        // 外部已经自定义 beforeUpload
        return bUpload(); // todo 未实现 promise
      }
      // 字节(Byte)、千字节(KB)、兆字节(MB)
      const sizeM = file.size / 1024 / 1024; // 转成兆
      const { minSize, maxSize } = this;
      if (minSize && minSize > sizeM) {
        this.$message.warning(
          `文件最小不能小于${this.minSize}兆(M)，请重新上传`
        );
        return false;
      }
      if (sizeM > maxSize) {
        // 不能大于1G
        this.$message.warning(
          `文件最大只能上传${this.maxSize}兆(M)，请重新上传`
        );
        return false;
      }
    },
    fileExceed() {
      // 文件超过限制
      this.$message.warning(`文件已超过最大限制`);
    },
    handleChange(file) {
      file.isUpload = true; // 用来区分 回显的/手动上传的
    },
    removeFile(file, fileList) {
      //文件列表移除文件时的钩子
      if (this.$props.onRemove) {
        this.onRemove(file, fileList);
      }
      this.$emit("change", fileList);
      this.$emit("customRemove", file, fileList);
    },
    changeFile(fileList) {
      if (fileList.length === 0) return [];
      if (this.uploadType === "dh") {
        // 大华
        return fileList.map((item) => {
          if (!item.response) {
            // 回显的数据没有response
            return item;
          }
          const data = item.response.data || {};
          const { httpUrl, fileUrl, zqHttpUrl } = data;
          return {
            name: "",
            url: zqHttpUrl, // 战勤数据库的地址
            uid: item.uid, // upload-list使用uid作为key。不改变uid避免动画闪缩
            prefixUrl: fileUrl,
            httpUrl,
          };
        });
      }
      // 战勤
      return fileList.map((item) => {
        if (!item.response) {
          // 回显的数据没有response
          return item;
        }
        const data = item.response.data || {};
        const { http_url, url, file_title } = data;
        return {
          url,
          http_url,
          uid: item.uid, // upload-list使用uid作为key。不改变uid避免动画闪缩
          name: file_title,
        };
      });
    },
    handleSuccess(res, file, list) {
      //文件上传成功时的钩子
      // todo 注意 回显的数据必须要有 status
      if (this.$props.httpRequest) {
        // 外部自定义上传的逻辑
        return;
      }
      const fileList = list.filter((item) => item.isUpload); // 排除回显的数据
      const isErr = fileList.some((item) => item.status !== "success"); // 多选情况全部上传完成后 status:success
      if (isErr) return;
      // isUpload:true 代表是手动上传的，跟接口回显的数据做区分
      const unSuccess = fileList.filter((item) => item.response?.code !== 200); // 未上传成功的
      if (unSuccess.length) {
        this.$confirm(
          `文件：${unSuccess.map(
            (item) => `<br><span>${item.name}</span>`
          )}<br><span style="color: red">上传失败</span>`,
          "提示",
          {
            confirmButtonText: "关闭",
            type: "warning",
            showCancelButton: false,
            dangerouslyUseHTMLString: true,
          }
        );
      }
      const arr = fileList.filter((item) => item.response?.code === 200); // 上传成功的
      const newList = this.changeFile(arr);
      const defaultList = list.filter((item) => !item.isUpload); // 拿到回显的数据
      this.$emit("change", [...defaultList, ...newList]);
    },
  },
  render() {
    const { action } = this.$props;
    const customProps = {
      ...this.$props,
      action: action || this.uploadUrl, // 必选参数，上传的地址
      beforeUpload: this.fileBeforeUpload, // 上传文件之前的钩子
      onExceed: this.fileExceed, // 文件超出个数限制时的钩子
      onSuccess: this.handleSuccess, // 文件上传成功时的钩子
      onChange: this.handleChange, // 文件上传成功时的钩子
      onRemove: this.removeFile, // 文件列表移除文件时的钩子
    };
    return (
      <Upload
        {...{
          props: customProps,
          attrs: {
            class: "c-upload",
            ...this.$attrs,
          },
          ref: "elUpload",
          on: {
            ...this.$listeners,
          },
        }}
      >
        {this.slotsVnode()}
      </Upload>
    );
  },
};

export default {
  install(Vue) {
    Vue.component(cUpload.name, cUpload);
  },
};
